package io.ripc.transport.netty4.tcp;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPromise;
import io.netty.channel.FixedRecvByteBufAllocator;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.json.JsonObjectDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import io.ripc.test.Publishers;
import io.ripc.protocol.tcp.TcpServer;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.Charset;
public class CodecSample {
private static final Logger LOG = LoggerFactory.getLogger(CodecSample.class);
public static void main(String... args) {
echoWithLineBasedFrameDecoder();
// echoJsonStreamDecoding();
}
private static void echoWithLineBasedFrameDecoder() {
TcpServer<String, String> server = Netty4TcpServer.create(
0,
new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
int bufferSize = 1024;
ChannelConfig config = channel.config();
config.setOption(ChannelOption.SO_RCVBUF, bufferSize);
config.setOption(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(bufferSize));
channel.pipeline().addFirst(
new LineBasedFrameDecoder(256),
new StringDecoder(CharsetUtil.UTF_8),
new StringEncoder(CharsetUtil.UTF_8));
}
});
server.start(conn -> {
conn.subscribe(new Subscriber<String>() {
private Subscription subscription;
@Override
public void onSubscribe(Subscription s) {
this.subscription = s;
LOG.info("requesting 1...");
s.request(1);
}
@Override
public void onNext(String s) {
LOG.info("onNext: {}", s);
conn.write(Publishers.just("Hello " + s + "\n"))
.subscribe(new Subscriber<Void>() {
@Override
public void onSubscribe(Subscription s) {
}
@Override
public void onNext(Void aVoid) {
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
LOG.info("requesting 1...");
subscription.request(1);
}
});
}
@Override
public void onError(Throwable t) {
LOG.error(t.getMessage(), t);
}
@Override
public void onComplete() {
LOG.info("onComplete");
}
});
return Publishers.just(null);
});
server.awaitShutdown();
}
private static void echoJsonStreamDecoding() {
TcpServer<Person, Person> server = Netty4TcpServer.<Person, Person>create(
0,
new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
channel.pipeline()
.addFirst(new JsonObjectDecoder(),
new JacksonJsonCodec());
}
});
server.start(conn -> {
conn.subscribe(new Subscriber<Person>() {
private Subscription subscription;
@Override
public void onSubscribe(Subscription s) {
this.subscription = s;
LOG.info("requesting 1...");
s.request(1);
}
@Override
public void onNext(Person p) {
LOG.info("onNext: {}", p);
conn.write(Publishers.just(new Person(p.getLastName(), p.getFirstName())))
.subscribe(new Subscriber<Void>() {
@Override
public void onSubscribe(Subscription s) {
}
@Override
public void onNext(Void aVoid) {
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
LOG.info("requesting 1...");
subscription.request(1);
}
});
}
@Override
public void onError(Throwable t) {
LOG.error(t.getMessage(), t);
}
@Override
public void onComplete() {
LOG.info("onComplete");
}
});
return Publishers.just(null);
});
server.awaitShutdown();
}
private static class JacksonJsonCodec extends ChannelDuplexHandler {
private final ObjectMapper mapper = new ObjectMapper();
@Override
public void channelRead(ChannelHandlerContext context, Object message) throws Exception {
if (message instanceof ByteBuf) {
Charset charset = Charset.defaultCharset();
message = this.mapper.readValue(((ByteBuf) message).toString(charset), Person.class);
}
super.channelRead(context, message);
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if (msg instanceof Person) {
byte[] buff = mapper.writeValueAsBytes(msg);
ByteBuf bb = ctx.alloc().buffer(buff.length);
bb.writeBytes(buff);
msg = bb;
}
super.write(ctx, msg, promise);
}
}
private static class Person {
private String firstName;
private String lastName;
public Person() {
}
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public Person setFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public String getLastName() {
return lastName;
}
public Person setLastName(String lastName) {
this.lastName = lastName;
return this;
}
}
}